package com.xuecheng.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.xuecheng.commons.enums.ErrorCode;
import com.xuecheng.commons.model.dto.CoursePubIndexDto;
import com.xuecheng.commons.model.dto.PageRequest;
import com.xuecheng.commons.model.vo.CoursePubIndexVo;
import com.xuecheng.commons.model.vo.CoursePubVo;
import com.xuecheng.commons.model.vo.PageResponseResult;
import com.xuecheng.commons.model.vo.ResponseResult;
import com.xuecheng.commons.utils.BeanHelper;
import com.xuecheng.content.api.ContentClient;
import com.xuecheng.search.domain.CoursePubIndex;
import com.xuecheng.search.service.SearchService;
import com.xuecheng.web.exceptions.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
@Service
public class SearchServiceImpl implements SearchService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Autowired
    private ContentClient contentClient;
    //条件查询
    @Override
    public PageResponseResult<CoursePubIndexVo> search(CoursePubIndexDto dto, PageRequest request) throws IOException {
        //1.构建查询条件
        //1.1创建searchRequest对象
        SearchRequest searchRequest = new SearchRequest("course");
        //1.2//创建查询条件
        SearchSourceBuilder builder = generatorBuilder(dto, request);
        //1.3将查询条件设置到searchRequest中
        searchRequest.source(builder);
        //2.发起请求
        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        //3.解析数据结果，并返回
        return parseResponse(response);
    }
    //同步es索引库
    @Override
    public void updateIndex(Long coursePubId) throws IOException {
        //1.根据id调用feign接口查询已发布数据
        ResponseResult<CoursePubVo> result = contentClient.findById(coursePubId);
        CoursePubVo vo = result.getData();
        //2.创建indexRequest对象
        IndexRequest request = new IndexRequest("course");
        //3.设置id，要转换的json数据
        request.id(vo.getId().toString());
        CoursePubIndex index = BeanHelper.copyProperties(vo, CoursePubIndex.class);
        index.setCourse_id(vo.getCourseId());
        index.setCompany_id(vo.getCompanyId());
        request.source(JSON.toJSONString(index), XContentType.JSON);
        //4.保存
        restHighLevelClient.index(request,RequestOptions.DEFAULT);
    }
    //根据id查询课程发布数据
    @Override
    public ResponseResult<CoursePubIndexVo> findById(Long id) throws IOException {
        //1.创建GetRequest对象
        GetRequest getRequest = new GetRequest("course",id.toString());
        //2.发送请求
        GetResponse response = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
        //3.解析响应
        String json = response.getSourceAsString();
        CoursePubIndex index = JSON.parseObject(json, CoursePubIndex.class);
        //转换index为vo对象
        CoursePubIndexVo vo = BeanHelper.copyProperties(index, CoursePubIndexVo.class);
        vo.setIndexId(index.getId());
        //4.返回
        return ResponseResult.okResult(vo);
    }
    //删除索引库数据
    @Override
    public void offlineIndex(Long coursePubId) throws IOException {
        //0.根据id查询，判断是否存在
        ResponseResult<CoursePubIndexVo> result = findById(coursePubId);
        if (result.getData() == null) {
            throw new BusinessException(ErrorCode.DELETEERROR);
        }
        //1.创建Request请求
        DeleteRequest deleteRequest = new DeleteRequest("course", coursePubId.toString());
        //2.删除
        restHighLevelClient.delete(deleteRequest,RequestOptions.DEFAULT);
    }

    //构建查询条件
    public SearchSourceBuilder generatorBuilder(CoursePubIndexDto dto, PageRequest request) {
        //创建查询条件
        SearchSourceBuilder builder = new SearchSourceBuilder();
        //设置分页参数
        builder.from((request.getPageNo() - 1) * request.getPageSize()).size(request.getPageSize());
        //bool条件
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        String keyword = dto.getKeyword();
        if (StringUtils.isNotEmpty(keyword)) {
            query.must(QueryBuilders.matchQuery("all", keyword));
        } else {
            query.must(QueryBuilders.matchAllQuery());
        }
        //添加筛选条件
        //大分类
        String mt = dto.getMt();
        if (StringUtils.isNotEmpty(mt)) {
            query.filter(QueryBuilders.termQuery("mt", mt));
        }
        //小分类
        String st = dto.getSt();
        if (StringUtils.isNotEmpty(st)) {
            query.filter(QueryBuilders.termQuery("st", st));
        }
        //难度
        String grade = dto.getGrade();
        if (StringUtils.isNotEmpty(grade)) {
            query.filter(QueryBuilders.termQuery("grade", grade));
        }
        builder.query(query);
        //设置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<font color=red>").postTags("</font>")
                .field("name").requireFieldMatch(false);
        builder.highlighter(highlightBuilder);
        return builder;
    }

    //解析响应结果
    public PageResponseResult parseResponse(SearchResponse response) {
        SearchHits hits = response.getHits();
        //获取解析结果数
        long value = hits.getTotalHits().value;
        //获取json集合
        SearchHit[] hitsHits = hits.getHits();
        //创建输出集合
        ArrayList<CoursePubIndexVo> vos = new ArrayList<>();
        for (SearchHit hitsHit : hitsHits) {
            String json = hitsHit.getSourceAsString();
            //将json转换成相应的对象
            CoursePubIndex index = JSON.parseObject(json, CoursePubIndex.class);
            //解析出高亮部分的name属性，替换到index中
            Map<String, HighlightField> map = hitsHit.getHighlightFields();
            if (map != null && map.containsKey("name")) {
                HighlightField nameField = map.get("name");
                String name = nameField.getFragments()[0].toString();
                index.setName(name);
            }
            //将index转换成vo
            CoursePubIndexVo vo = BeanHelper.copyProperties(index, CoursePubIndexVo.class);
            vo.setIndexId(index.getId());
            //添加到要输出的集合中
            vos.add(vo);
        }
        return new PageResponseResult(value,vos);
    }

}
